package com.ideaaedi.mybatis.data.security.support;

import com.ideaaedi.mybatis.data.security.annotation.Encrypt;
import com.ideaaedi.mybatis.data.security.enums.TypeEnum;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.ibatis.annotations.Param;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.ARRAY;
import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.COLLECTION;
import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.CUSTOM_BEAN;
import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.MAP;
import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.PRIMITIVE_OR_WRAPPER;
import static com.ideaaedi.mybatis.data.security.enums.TypeEnum.STRING;


/**
 * 加解密信息持有器<br/><br/>
 *
 * 本类虽然涉及有方法解析，但是由于非常简单，所以就自己写了。如果你需要全面解析java代码，但是你又没有时间或精力去自己写，那么你可以考虑使用这两款工具：<br/>
 * <ul>
 *     <li><a href="https://github.com/javaparser/javaparser">JavaParser</a>：强大、全面，学习曲线较峭</li>
 *     <li><a href="https://github.com/paul-hammant/qdox">QDox</a>：基本够用，学习曲线较缓</li>
 *
 * </ul>
 *
 * @author JustryDeng
 * @since 2021/2/10 22:48:44
 */
public class EncryptInfoHolder {
    
    private EncryptInfoHolder() {
    }
    
    /** sql对应的MappedStatement对象的Id */
    private String mappedStatementId;
    
    /** mappedStatementId对应的方法 */
    private Method targetMethod;
    
    /** 参数与参数的注解map */
    private Map<Parameter, Annotation[]> paramAnnotationMap;
    
    /** 返回值类型 */
    private Class<?> returnClass;
    
    /** 是否需要加密 */
    private boolean needEncrypt;
    
    /** 要加密的bean信息 */
    private List<BeanEncryptDetailInfo> encryptBeanInfoList;
    
    /** 要加密的参数信息 */
    private ParamEncryptDetailInfo encryptParamInfo;
    
    /** 是否需要解密 */
    private boolean needDecrypt;
    
    /** 要解密的bean信息 */
    private BeanEncryptDetailInfo decryptBeanInfo;
    
    public String getMappedStatementId() {
        return mappedStatementId;
    }
    
    private void setMappedStatementId(String mappedStatementId) {
        this.mappedStatementId = mappedStatementId;
    }
    
    public Method getTargetMethod() {
        return targetMethod;
    }
    
    private void setTargetMethod(Method targetMethod) {
        this.targetMethod = targetMethod;
    }
    
    public Map<Parameter, Annotation[]> getParamAnnotationMap() {
        return paramAnnotationMap;
    }
    
    private void setParamAnnotationMap(Map<Parameter, Annotation[]> paramAnnotationMap) {
        this.paramAnnotationMap = paramAnnotationMap;
    }
    
    public Class<?> getReturnClass() {
        return returnClass;
    }
    
    private void setReturnClass(Class<?> returnClass) {
        this.returnClass = returnClass;
    }
    
    public boolean isNeedEncrypt() {
        return needEncrypt;
    }
    
    private void setNeedEncrypt(boolean needEncrypt) {
        this.needEncrypt = needEncrypt;
    }
    
    public List<BeanEncryptDetailInfo> getEncryptBeanInfoList() {
        return encryptBeanInfoList;
    }
    
    private void setEncryptBeanInfoList(List<BeanEncryptDetailInfo> encryptBeanInfoList) {
        this.encryptBeanInfoList = encryptBeanInfoList;
    }
    
    public ParamEncryptDetailInfo getEncryptParamInfo() {
        return encryptParamInfo;
    }
    
    private void setEncryptParamInfo(ParamEncryptDetailInfo encryptParamInfo) {
        this.encryptParamInfo = encryptParamInfo;
    }
    
    public boolean isNeedDecrypt() {
        return needDecrypt;
    }
    
    private void setNeedDecrypt(boolean needDecrypt) {
        this.needDecrypt = needDecrypt;
    }
    
    public BeanEncryptDetailInfo getDecryptBeanInfo() {
        return decryptBeanInfo;
    }
    
    private void setDecryptBeanInfo(BeanEncryptDetailInfo decryptBeanInfo) {
        this.decryptBeanInfo = decryptBeanInfo;
    }
    
    @Override
    public String toString() {
        return "EncryptInfoHolder{" +
                "mappedStatementId='" + mappedStatementId + '\'' +
                ", targetMethod=" + targetMethod +
                ", paramAnnotationMap=" + paramAnnotationMap +
                ", returnClass=" + returnClass +
                ", needEncrypt=" + needEncrypt +
                ", encryptBeanInfoList=" + encryptBeanInfoList +
                ", encryptParamInfo=" + encryptParamInfo +
                ", needDecrypt=" + needDecrypt +
                ", decryptBeanInfo=" + decryptBeanInfo +
                '}';
    }
    
    /**
     * bean的具体加密/解密信息
     */
    public static class BeanEncryptDetailInfo {
        
        private BeanEncryptDetailInfo() {
        }
    
        /** 字段-加解密信息 map */
        private Map<Field, Encrypt> fieldEncryptMap;
    
        /** 当前BeanEncryptDetailInfo对象所执行的bean的类型 */
        private Class<?> beanClass;
        
        /**
         * 创建BeanEncryptDetailInfo实例
         *
         * @param beanClass
         *            待解析的class
         * @return  BeanEncryptDetailInfo实例
         */
        @NonNull
        public static  BeanEncryptDetailInfo build(Class<?> beanClass) {
            BeanEncryptDetailInfo beanEncryptDetailInfo = new BeanEncryptDetailInfo();
            beanEncryptDetailInfo.setBeanClass(beanClass);
            beanEncryptDetailInfo.setFieldEncryptMap(extractBeanFieldEncryptInfo(beanClass));
            return beanEncryptDetailInfo;
        }
        
        /**
         * 解析beanClass中的@Encrypt注解
         *
         * @param beanClass
         *            待解析的class
         * @return  class中的 字段-加密信息map
         */
        public static  Map<Field, Encrypt> extractBeanFieldEncryptInfo(Class<?> beanClass) {
            Map<Field, Encrypt> infoMap = new HashMap<>(8);
            ReflectionUtils.doWithFields(beanClass, (Field field) ->{
                Encrypt annotation = field.getAnnotation(Encrypt.class);
                if (annotation != null) {
                    // [强制约束] 当@Encrypt应用于ElementType.FIELD上时，对应的字段类型必须是String
                    Class<?> fieldType = field.getType();
                    if (TypeUtils.isAssignable(fieldType, String.class)) {
                        infoMap.put(field, annotation);
                    } else {
                        throw new IllegalArgumentException(
                                String.format("@Encrypt is not allowed to apply at type [%s], only for String,class. @see %s",
                                        fieldType, beanClass.getName())
                        );
                    }
                }
            });
            // 根据Encrypt的order值对map进行排序
            return new ArrayList<>(infoMap.entrySet()).stream()
                    .sorted(Comparator.comparing(fieldEncryptEntry -> fieldEncryptEntry.getValue().order()))
                    .collect(
                            Collectors.toMap(
                                    Map.Entry::getKey,
                                    Map.Entry::getValue,
                                    (u, v) -> {
                                        throw new IllegalStateException("Duplicate key " + u);
                                    },
                                    LinkedHashMap::new
                            )
                    );
        }
    
        public Map<Field, Encrypt> getFieldEncryptMap() {
            return fieldEncryptMap;
        }
    
        private void setFieldEncryptMap(Map<Field, Encrypt> fieldEncryptMap) {
            this.fieldEncryptMap = fieldEncryptMap;
        }
    
        public Class<?> getBeanClass() {
            return beanClass;
        }
    
        private void setBeanClass(Class<?> beanClass) {
            this.beanClass = beanClass;
        }
    
        @Override
        public String toString() {
            return "BeanEncryptDetailInfo{" +
                    "fieldEncryptMap=" + fieldEncryptMap +
                    ", beanClass=" + beanClass +
                    '}';
        }
    }
    
    /**
     * ElementType.PARAMETER 参数的具体加密=信息
     */
    public static class ParamEncryptDetailInfo {
    
        private ParamEncryptDetailInfo() {
        }
    
        public static final ParamEncryptDetailInfo EMPTY = new  ParamEncryptDetailInfo();
    
        /** ({@link Param}注解指定的)参数名 - 加解密信息 map */
        private Map<String, Encrypt> paramEncryptMap;
    
        public Map<String, Encrypt> getParamEncryptMap() {
            return paramEncryptMap;
        }
    
        private void setParamEncryptMap(Map<String, Encrypt> paramEncryptMap) {
            this.paramEncryptMap = paramEncryptMap;
        }
    
        @Override
        public String toString() {
            return "ParamEncryptDetailInfo{" +
                    "paramEncryptMap=" + paramEncryptMap +
                    '}';
        }
    }
    
    /**
     * EncryptInfoHolder工厂
     */
    public static class Factory {
        
        private static final Logger log = LoggerFactory.getLogger(Factory.class);
        
        /** 泛型左符号 */
        private static final String GENERIC_LEFT_SIGN = "<";
        
        /** 泛型右符号 */
        private static final String GENERIC_RIGHT_SIGN = ">";
        
        /** 获取方法签名的Method */
        private static final Method GET_GENERIC_SIGNATURE;
        
        static {
            GET_GENERIC_SIGNATURE = ReflectionUtils.findMethod(Method.class, "getGenericSignature");
            //noinspection ConstantConditions
            GET_GENERIC_SIGNATURE.setAccessible(true);
        }
        
        /**
         * 创建EncryptInfoHolder实例
         */
        public static EncryptInfoHolder create(String mappedStatementId, Method targetMethod, Parameter[] parameters,
                                               Annotation[][] paramAnnotations, Class<?> returnClass) {
            EncryptInfoHolder instance = new EncryptInfoHolder();
            instance.setMappedStatementId(mappedStatementId);
            instance.setTargetMethod(targetMethod);
            Map<Parameter, Annotation[]> tmpMap = new HashMap<>(8);
            for (int i = 0; i < parameters.length; i++) {
                tmpMap.put(parameters[i], paramAnnotations[i]);
            }
            instance.setParamAnnotationMap(tmpMap);
            instance.setReturnClass(returnClass);
    
            Pair<List<BeanEncryptDetailInfo>, ParamEncryptDetailInfo> encryptPair = analyzeEncryptDetailInfo(mappedStatementId, tmpMap);
            instance.setEncryptBeanInfoList(encryptPair.getLeft());
            instance.setEncryptParamInfo(encryptPair.getRight());
            boolean needEncrypt = (!CollectionUtils.isEmpty(instance.getEncryptBeanInfoList()))
                    || (!CollectionUtils.isEmpty(instance.getEncryptParamInfo().getParamEncryptMap()));
            instance.setNeedEncrypt(needEncrypt);
            
            BeanEncryptDetailInfo decryptBeanInfo = analyzeDecryptDetailInfo(targetMethod, returnClass);
            instance.setDecryptBeanInfo(decryptBeanInfo);
            boolean needDecrypt = decryptBeanInfo != null && (!CollectionUtils.isEmpty(decryptBeanInfo.fieldEncryptMap));
            instance.setNeedDecrypt(needDecrypt);
            log.debug("EncryptInfoHolder$Factory parse mappedStatementId [{}], create instance -> {}", mappedStatementId, instance);
            return instance;
        }
        
        /**
         * 分析加密信息详情
         *
         * @param mappedStatementId
         *            sql对应的mappedStatementId
         * @param paramAnnotationMap
         *            参数与注解map
         * @return  加密信息详情
         *  <ul>
         *      <li>左 - 对bean的具体加密信息</li>
         *      <li>右 - 对参数的具体加密信息</li>
         *  </ul>
         */
        private static Pair<List<BeanEncryptDetailInfo>, ParamEncryptDetailInfo> analyzeEncryptDetailInfo(String mappedStatementId, Map<Parameter, Annotation[]> paramAnnotationMap) {
            List<BeanEncryptDetailInfo> encryptBeanInfoList = new ArrayList<>(8);
            ParamEncryptDetailInfo encryptParamInfo = new ParamEncryptDetailInfo();
            Map<String, Encrypt> paramEncryptMap = new HashMap<>(8);
            encryptParamInfo.setParamEncryptMap(paramEncryptMap);
            // 遍历参数进行解析
            paramAnnotationMap.forEach((param, annotations) -> {
                Class<?> type = param.getType();
                TypeEnum typeEnum = TypeEnum.parseType(type);
                // [强制约束] 当@Encrypt应用于ElementType.PARAMETER前时，参数项类型必须是String,不能是其它的
                if (typeEnum != STRING) {
                    for (Annotation annotation : annotations) {
                        if (annotation instanceof Encrypt) {
                            throw new IllegalArgumentException(String.format("@Encrypt is not allowed to apply at type [%s]. @see %s",
                                    type, mappedStatementId));
                        }
                    }
                }
                // 如果是基础类型或者是其包装类型就跳过
                if (typeEnum == PRIMITIVE_OR_WRAPPER) {
                    return;
                }
                // string
                if (typeEnum == STRING) {
                    Encrypt encryptAnnotation = (Encrypt)Arrays.stream(annotations).filter(x -> x instanceof Encrypt).findFirst().orElse(null);
                    Param paramAnnotation = (Param)Arrays.stream(annotations).filter(x -> x instanceof Param).findFirst().orElse(null);
                    // [强制约束] 当@Encrypt应用于ElementType.PARAMETER前时，还需同时使用@Param指定名称
                    if (encryptAnnotation != null) {
                        if (paramAnnotation == null) {
                            throw new IllegalArgumentException(String.format("While use @Encrypt in case ElementType.PARAMETER, "
                                            + "must use @Param at the same time. @see %s", mappedStatementId));
                        }
                        paramEncryptMap.put(paramAnnotation.value(), encryptAnnotation);
                    }
                    return;
                }
                // map、collection、array
                if (typeEnum == MAP || typeEnum == COLLECTION || typeEnum == ARRAY) {
                    Pair<TypeEnum, Class<?>> typeEnumClassPair = parseInnermostType(param, mappedStatementId);
                    if (typeEnumClassPair.getLeft() == CUSTOM_BEAN) {
                        BeanEncryptDetailInfo info = BeanEncryptDetailInfo.build(typeEnumClassPair.getRight());
                        if (!CollectionUtils.isEmpty(info.getFieldEncryptMap())) {
                            encryptBeanInfoList.add(info);
                        }
                    }
                    return;
                }
                if (typeEnum == CUSTOM_BEAN) {
                    BeanEncryptDetailInfo info = BeanEncryptDetailInfo.build(type);
                    if (!CollectionUtils.isEmpty(info.getFieldEncryptMap())) {
                        encryptBeanInfoList.add(info);
                    }
                } else {
                    log.debug("Ignore analyze bean of type [{}]. @see {}", type.getName(), mappedStatementId);
                }
            });
            return Pair.of(encryptBeanInfoList, encryptParamInfo);
        }
    
        /**
         * 根据返回值类型，判断是否需要解密
         * <p>
         *     理论支持：如果方法的参数或者返回值存在显示指定的泛型时，为了避免因泛型擦除而导致在某些场景下的定位混乱，所以JVM会为那些有泛型的方法生成签名，如：
         *     <ul>
         *         <li>1. Map method1(@Param("name") String name);
         *             <br>
         *             null  这种不指定具体泛型的，是不会生成签名的（即：获取到的签名为null）.
         *         </li>
         *         <li>
         *             2. Map method2(@Param("p") Map<String, Object> paramsMap);
         *             <br>
         *             (Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)Ljava/util/Map;
         *         </li>
         *         <li>
         *             3. Map<String, Object> method3(@Param("id") Integer id);
         *             <br>
         *             (Ljava/lang/Integer;)Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;
         *         </li>
         *         <li>
         *             4， int method4(@Param("p") Map<String, Object> paramsMap);
         *             <br>
         *             (Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)I
         *         </li>
         *         <li>
         *             5. List<Map<String, Object>> method5(@Param("name") String name);
         *             <br>
         *             (Ljava/lang/String;)Ljava/util/List<Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;>;
         *         </li>
         *         <li>
         *             6. List<Employee> method6();
         *             <br>
         *             ()Ljava/util/List<Lcom/aspire/ssm/model/Employee;>;
         *         </li>
         *         <li>
         *             7. Employee[] method7(@Param("p") Map<String, Object> paramsMap);
         *             <br>
         *             (Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)[Lcom/aspire/ssm/model/Employee;
         *         </li>
         *         <li>
         *             8. Employee[][] method8(@Param("p") Map<String, Object> paramsMap);
         *             <br>
         *             (Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)[[Lcom/aspire/ssm/model/Employee;
         *         </li>
         *         <li>
         *             9。 Map method9(@Param("p1") Map<String, Object> paramsMap1, @Param("p2") Map<String, Object> paramsMap2);
         *             <br>
         *             (Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;)Ljava/util/Map;
         *         </li>
         *     </ul>
         * </p>
         * <p>
         *     提示：简单的，可以使用以下代码输出类(如AbcMapper)中所有方法的签名
         *     <code>
         *           Method getGenericSignature = ReflectionUtils.findMethod(Method.class, "getGenericSignature");
         *           getGenericSignature.setAccessible(true);
         *           Method[] declaredMethods = AbcMapper.class.getDeclaredMethods();
         *           for (Method declaredMethod : declaredMethods) {
         *               System.err.println(i + "\t" + ReflectionUtils.invokeMethod(getGenericSignature, declaredMethod));
         *           }
         *     </code>
         * </p>
         */
        @SuppressWarnings("AlibabaUndefineMagicConstant")
        @Nullable
        private static BeanEncryptDetailInfo analyzeDecryptDetailInfo(Method targetMethod, Class<?> returnClass){
            TypeEnum typeEnum = TypeEnum.parseType(returnClass);
            if (typeEnum == CUSTOM_BEAN) {
                return BeanEncryptDetailInfo.build(returnClass);
            }
            if (typeEnum == MAP || typeEnum == COLLECTION) {
                Object getGenericSignature = ReflectionUtils.invokeMethod(GET_GENERIC_SIGNATURE, targetMethod);
                // 返回值没有明确的指定泛型，如上面的示例1
                if (getGenericSignature == null) {
                    return null;
                }
                // 返回值没有明确的指定泛型，但由于参数存在泛型，导致getGenericSignature不为null的情况，如上面的示例2
                String signature = getGenericSignature.toString();
                String returnObjSignature = signature.substring(signature.lastIndexOf(")") + 1);
                int startIndex = returnObjSignature.indexOf(GENERIC_LEFT_SIGN);
                int endIndex = returnObjSignature.lastIndexOf(GENERIC_RIGHT_SIGN);
                if (startIndex == -1 || endIndex == -1) {
                    return null;
                }
                // 此时，获取到的泛型，在上述示例3中体现为 Ljava/lang/String;Ljava/lang/Object;
                // 此时，获取到的泛型，在上述示例5中体现为 Ljava/util/Map<Ljava/lang/String;Ljava/lang/Object;>;
                String genericInfo = returnObjSignature.substring(startIndex + 1, endIndex);
                // [强制约束] 不支持泛型嵌套泛型这样的复杂写法(如上述示例5)，快速失败，使项目启动不起来
                if (genericInfo.contains(GENERIC_LEFT_SIGN) || genericInfo.contains(GENERIC_RIGHT_SIGN)) {
                    throw new UnsupportedOperationException(String.format("Cannot support return-type Generics nested Generics. @see %s", targetMethod));
                }
                // 逻辑到这里，已经保证了返回值的有泛型，且泛型一定是(类似于上述示例3那样的)非嵌套泛型
                // Map的泛型是k-v的形式，要获取第二个； Collection直接获取第一个
                int genericInfoIndex = typeEnum == MAP ? 1 : 0;
                String onlyGenericInfo = genericInfo.split(";")[genericInfoIndex];
                // [强制约束] 不允许泛型是数组，快速失败，使项目启动不起来
                if (onlyGenericInfo.startsWith("[")) {
                    throw new UnsupportedOperationException(String.format("Cannot support return-type Generics exist Array. @see %s", targetMethod));
                }
                // (因为基本类型不能作为泛型且上面考虑了数组的情况，所以)到这里onlyGenericInfo就一定是L打头的了， L表示对象类型， 即：此时，onlyGenericInfo的值形如 Lcom/aspire/ssm/model/Employee
                String elementClassName = onlyGenericInfo.substring(1).replace("/", ".");
                Class<?> elementClass;
                try {
                    elementClass = Class.forName(elementClassName);
                }catch (ClassNotFoundException e) {
                    throw new IllegalStateException(String.format("Cannot find class [%s], while signature is [%s]. targetMethod is [%s].",
                            elementClassName, signature, targetMethod), e);
                }
                typeEnum = TypeEnum.parseType(elementClass);
                if (typeEnum == CUSTOM_BEAN) {
                    return BeanEncryptDetailInfo.build(elementClass);
                } else {
                    return null;
                }
            }
            if (typeEnum == ARRAY) {
                String clazzName = returnClass.getName();
                // [强制约束] 返回值类型不能是多维数组
                if (clazzName.startsWith("[[")) {
                    throw new UnsupportedOperationException(String.format("Cannot support return-type is multidimensional Array. @see %s", targetMethod));
                }
                if (!clazzName.startsWith("[L")) {
                    // 如果不是对象数组 (如:是基本类型数组)的话，直接返回null
                    return null;
                }
                // 逻辑到这里，即保证了返回值类型一定是一维数组，且是一维非基本类型数组
                // 去掉开头的[L和结尾;号
                clazzName = clazzName.substring(2, clazzName.length() - 1);
                Class<?> beanClass;
                try {
                    beanClass = Class.forName(clazzName);
                    typeEnum = TypeEnum.parseType(beanClass);
                    return typeEnum == CUSTOM_BEAN ? BeanEncryptDetailInfo.build(beanClass) : null;
                } catch (ClassNotFoundException e) {
                    throw new IllegalStateException(String.format("Cannot find class [%s], targetMethod is [%s].",
                            clazzName, targetMethod), e);
                }
            }
            return null;
        }

        /**
         * 解析parameter的里层数据类型
         * <p>
         *     示例：
         *     <ul>
         *         <li>Collection<E> => 最里层的bean类型为E</li>
         *         <li>Map<K, V> => 最里层的bean类型为v</li>
         *         <li>一维数组[A] => 最里层的bean类型为A</li>
         *         <li>......</li>
         *     </ul>
         * </p>
         *
         * @param parameter
         *            待解析的参数信息
         * @param mappedStatementId
         *            mappedStatementId可定位parameter所在方法的
         * @return  <ul>
         *              <li>左 - 数据类型</li>
         *              <li>右 - 具体的class</li>
         *          </ul>
         *          <p>注：此方法返回的TpeEnum,不可能为COLLECTION或MAP或ARRAY</p>
         */
        private static Pair<TypeEnum, Class<?>> parseInnermostType(Parameter parameter, String mappedStatementId) {
            Class<?> clazz = parameter.getType();
            TypeEnum typeEnum = TypeEnum.parseType(clazz);
            switch (typeEnum) {
                case PRIMITIVE_OR_WRAPPER:
                case STRING:
                case CUSTOM_BEAN:
                case SYSTEM_BEAN:
                    return Pair.of(typeEnum, clazz);
                case COLLECTION:
                case MAP:
                    Type parameterizedType = parameter.getParameterizedType();
                    if (parameterizedType instanceof ParameterizedTypeImpl) {
                        // 集合只有一个泛型，所以解析index=0的泛型；MAP解析value的类型，所以解析index=1的泛型
                        int targetTypeIndex = typeEnum == COLLECTION ? 0 : 1;
                        String genericClassName = ((ParameterizedTypeImpl) parameterizedType).getActualTypeArguments()[targetTypeIndex].getTypeName();
                        Class<?> genericClass;
                        try {
                            genericClass = Class.forName(genericClassName);
                        } catch (ClassNotFoundException e) {
                            throw new IllegalArgumentException(String.format("Cannot load class [%s]. At param [%s]. @see %s",
                                    genericClassName, parameter.getName(), mappedStatementId));
                        }
                        TypeEnum genericTypeEnum = TypeEnum.parseType(genericClass);
                        // fail fast不支持复杂的泛型(如：泛型嵌套泛型等)
                        if (genericTypeEnum == MAP || genericTypeEnum == COLLECTION || genericTypeEnum == ARRAY) {
                            throw new UnsupportedOperationException(String.format("Cannot support parse complex Generics nested Generics. "
                                    + "At param[%s]. @see %s", parameter.getName(), mappedStatementId));
                        }
                        return Pair.of(genericTypeEnum, genericClass);
                    } else {
                        // fail fast不支持解析非ParameterizedTypeImpl类型的泛型
                        throw new UnsupportedOperationException(String.format("Cannot support parse non-ParameterizedTypeImpl Generics. "
                                        + "Maybe you should point specific generics at param[%s]. @see %s", parameter.getName(), mappedStatementId));
                    }
                case ARRAY:
                    Type arrayComponentType = TypeUtils.getArrayComponentType(clazz);
                    if (arrayComponentType instanceof Class<?>) {
                        Class<?> arrayComponentClazz = (Class<?>)arrayComponentType;
                        TypeEnum arrayComponentTypeEnum = TypeEnum.parseType(arrayComponentClazz);
                        // fail fast不支持复杂的数组嵌套
                        if (arrayComponentTypeEnum == MAP || arrayComponentTypeEnum == COLLECTION || arrayComponentTypeEnum == ARRAY) {
                            throw new UnsupportedOperationException(String.format("Cannot support parse complex nesting Array. At param[%s]. @see %s",
                                    parameter.getName(), mappedStatementId));
                        }
                        return Pair.of(arrayComponentTypeEnum, arrayComponentClazz);
                    } else {
                        // fail fast不支持解析非Class的实现
                        throw new UnsupportedOperationException(String.format("Cannot support parse non-Class Type. "
                                + "At param[%s]. @see %s", parameter.getName(), mappedStatementId));
                    }
                default:
                    throw new UnsupportedOperationException(String.format("Cannot support for typeEnum [%s] At param [%s]. @see %s",
                            typeEnum, parameter.getName(), mappedStatementId));
            }
    
        }
    }
}
